package com.veetao.api.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.veetao.api.model.ApiCommand;
import com.veetao.api.model.ApiFacade;
import com.veetao.api.service.CommandLookupService;
import com.veetao.api.utils.CommandModelUtils;

@Service
public class CommandLookupServiceImpl implements CommandLookupService, InitializingBean {

	private static final Log logger = LogFactory.getLog(CommandLookupServiceImpl.class);

	@Autowired
	private Collection<ApiFacade> apiFacadeList;

//	private final Map<String, List<String>> allCommands = new HashMap<String, List<String>>();
	
	private final Map<String, Map<String, ApiCommand>> commandContainer = new HashMap<String, Map<String, ApiCommand>>();

	@Override
	public ApiCommand lookupApiCommand(String methodName, String version) {
		Map<String, ApiCommand> apis = commandContainer.get(methodName);
		if (apis == null) {
			return null;
		}
		if (apis.size() == 1) {
			return apis.values().iterator().next();
		}
		if (version == null || version.isEmpty() || "1.0".equals(version)) {
			return apis.get("1.0");
		}
		
		if(apis.containsKey(version)) {
			return apis.get(version);
		}
		
		
		BigDecimal d = new BigDecimal(version);
		
		BigDecimal versionStepDecimal = new BigDecimal("0.1");
		while(d.floatValue() > 1.0) {
			// 向下找到第一个版本符合的方法
			d = d.subtract(versionStepDecimal);
			ApiCommand method2 = apis.get(d.floatValue()+"");
			if(method2 != null) {
				// 记住这个方法，避免每次都向下遍历查找
				apis.put(version, method2);
				return method2;
			}
		}
		
		return null;
	}


	@Override
	public boolean isNeedLogin(String methodName, String version) {
		if(methodName.startsWith("admin.")) {
			return false;
		}
		final ApiCommand cmd = lookupApiCommand(methodName, version);
		if (cmd == null) {
			return false;
		}
		return cmd.getMcpMethod().logon();
	}

	@Override
	public Map<String, List<String>> getCommands() {
		
		Map<String, List<String>> allCommands = new HashMap<String, List<String>>();
		for(String methodName : this.commandContainer.keySet()) {
			if(!allCommands.containsKey(methodName)) {
				allCommands.put(methodName, new ArrayList<String>());
			}
			for(String ver : this.commandContainer.get(methodName).keySet()) {
				allCommands.get(methodName).add(ver);
			}
		}
		
		
		return allCommands;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
		
		//Map<Class<?>, List<ApiCommandWrapper>> methodModelMap = new ConcurrentHashMap<Class<?>, List<ApiCommandWrapper>>();
		for (ApiFacade apiFacade : apiFacadeList) {
//			if(methodModelMap.containsKey(apiFacade.getClass())) {
//				continue;
//			}
			
			List<ApiCommand> ls = CommandModelUtils.getMethodModelList(apiFacade);
			
			logger.info(apiFacade.toString());
			for (ApiCommand method : ls) {
				final String methodName = method.getMcpMethod().name();
				final String version = method.getMcpMethod().ver();
				logger.info(method.toString());
				Map<String,ApiCommand> commands = this.commandContainer.get(methodName);
				if (commands == null) {
					commands = new HashMap<String,ApiCommand>();
					commandContainer.put(methodName, commands);
				} else if (commands.containsKey(version)) {
					final String errorMsg = String.format("ApiFacade load error, %s exist %s[%s/%s], exit."//
							, method.getTargetObject().getClass().getName()//
							, method.getMethod().getName()//
							, methodName, methodName//
					);
					Assert.notNull(null, errorMsg);
				}
				commands.put(version, method);
				if (logger.isDebugEnabled()) {
					logger.debug(String.format("ApiFacade load %s: %s[%s]"//
							, method.getTargetObject().getClass().getName()//
							, method.getMethod().getName()//
							, methodName//
					));
				}
			}
		}
	}

	@Override
	public boolean needCheckSignature(String methodName, String version) {
		final ApiCommand cmd = lookupApiCommand(methodName, version);
		if (cmd == null) {
			return false;
		}
		return cmd.getMcpMethod().checkSig();
	}

}
